/*-
 * Scala tree grammar for building the symbol maps.
 *
 * Copyright (c) 2010 Alex Suhan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer
 * in this position and unchanged.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

tree grammar ScalaMapsBuilder;

options {
    tokenVocab = ScalaTreeBuilder;
    ASTLabelType = CommonTree;
}

@members {
    static ScalaClassTable classTable = new ScalaClassTable();
    
    static InheritanceGraph<String> inhGraph =
        new InheritanceGraph<String>();
    
    private static void error(int line, int pos, String message)
    {
        System.err.println("" + line + ":" + pos + ": " + message);
        System.exit(-1);
    }

    static String crtFileName;
}

program
    :    ^(DiceProgram classDef+) ;

classDef
    :    ^(Class ^(Name name=ID)
        {
            String baseClass = ScalaConstants.ObjectClassname;
        }
        (^(BaseClass base=ID) { baseClass = $base.text; inhGraph.addLink($name.text, $base.text); })?
        {
            ScalaClassInfo classInfo = new ScalaClassInfo(baseClass, crtFileName);
            classTable.put($name.text, classInfo);
        }
        features [classInfo])
    ;

features [ScalaClassInfo classInfo]
    :    ^(Features
        (feature
        {
            if ($feature.info instanceof ScalaMethodInfo)
            {
                ScalaFeatureInfo oldInfo =
                    classInfo.putMethod($feature.key, (ScalaMethodInfo) $feature.info);
                if (oldInfo != null)
                    error($feature.line, $feature.pos, "illegal '" + $feature.key + "' method redefinition");
            }
            else if ($feature.info instanceof ScalaAttrInfo)
            {
                ScalaFeatureInfo oldInfo =
                    classInfo.putAttribute($feature.key, (ScalaAttrInfo) $feature.info);
                if (oldInfo != null)
                    error($feature.line, $feature.pos, "illegal '" + $feature.key + "' attribute redefinition");
            }
        }
        )*)
    ;

feature returns [String key, ScalaFeatureInfo info, int line, int pos]
    :    {
            boolean isOverride = false;
        }
        ^(FeatureMethod (KW_OVERRIDE { isOverride = true; })? ^(Name name=ID)
        {
            $key = $name.text;
            $line = $FeatureMethod.line;
            $pos = $FeatureMethod.pos;
            String returnType = ScalaConstants.NoTypeClassname;
        }
        (^(Type type=ID) { returnType = $type.text; })?
        {
            ScalaFormals formals = new ScalaFormals();
        }
        ^(FormalParams (formal { formals.add($formal.info); })*) .)
        {
            $info = new ScalaMethodInfo(returnType, formals, isOverride);
        }
    |    ^(FeatureAttrib ^(Name name=ID)
        {
            $key = $name.text;
            $line = $FeatureAttrib.line;
            $pos = $FeatureAttrib.pos;
        }
        ^(Type type=ID) .?)
        {
            $info = new ScalaAttrInfo($type.text);
        }
    ;

formal returns [ScalaFormal info]
    :    ^(Formal ^(Name name=ID) ^(Type type=ID))
    {
        $info = new ScalaFormal($name.text, $type.text);
    }
    ;
